﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Xml.Linq;
using HigLabo.Net;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

namespace HigLabo.Net.Twitter
{
    /// <summary>
    /// 
    /// </summary>
    public partial class TwitterClient : OAuth1Client
    {
        public static readonly TwitterClientDefaultSettings Default = new TwitterClientDefaultSettings();
        /// <summary>
        /// 
        /// </summary>
        public HttpProtocolType Protocol { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public TwitterApiResponseFormat Format { get; private set; }

        public TwitterClient()
            : this(Default.ConsumerKey, Default.ConsumerSecret)
        {
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="consumerKey"></param>
        /// <param name="consumerSecret"></param>
        /// <param name="accessToken"></param>
        /// <param name="accessTokenSecret"></param>
        public TwitterClient(String consumerKey, String consumerSecret)
            : base(consumerKey, consumerSecret
                , "https://" + TwitterApiUrl.Version1_1.OAuth.RequestToken
                , "https://" + TwitterApiUrl.Version1_1.OAuth.AuthorizeToken
                , "https://" + TwitterApiUrl.Version1_1.OAuth.AccessToken)
        {
            this.Mode = OAuthMode.Header;
            this.Protocol = HttpProtocolType.Https;
            this.Format = TwitterApiResponseFormat.Json;
            this.AccessToken = new OAuth1AccessToken();
            this.AccessToken.SetProperty(Default.AccessToken);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="url"></param>
        /// <param name="callback"></param>
        private void GetResultText(String url, Action<String> callback)
        {
            this.GetResultText(HttpMethodName.Get, url, null, callback);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="methodName"></param>
        /// <param name="url"></param>
        /// <param name="callback"></param>
        private void GetResultText(HttpMethodName methodName, String url, Action<String> callback)
        {
            this.GetResultText(methodName, url, null, callback);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="url"></param>
        /// <param name="command"></param>
        /// <param name="callback"></param>
        private void GetResultText(String url, TwitterCommand command, Action<String> callback)
        {
            this.GetResultText(HttpMethodName.Get, url, command, callback);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="methodName"></param>
        /// <param name="url"></param>
        /// <param name="command"></param>
        /// <param name="callback"></param>
        private void GetResultText(HttpMethodName methodName, String url, TwitterCommand command, Action<String> callback)
        {
            String u = this.Protocol.ToString().ToLower() + "://" + url;
            IDictionary<String, String> d = new Dictionary<string, string>();

            if (methodName == HttpMethodName.Put ||
                methodName == HttpMethodName.Delete)
            { throw new ArgumentException(); }

            if (command != null)
            {
                d = command.GetParameters();
            }
            this.GetResponse(methodName, u, this.AccessToken.Token, this.AccessToken.TokenSecret, d, res => callback(res.BodyText));
        }


        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="text"></param>
        /// <param name="xElementKey"></param>
        /// <returns></returns>
        protected List<T> CreateResponseObjectList<T>(String text, String xElementKey)
            where T : ResponseObject, new ()
        {
            List<T> l = new List<T>();
            T rs;

            switch (this.Format)
            {
                case TwitterApiResponseFormat.Xml:
                    foreach (var x in XElement.Parse(text).Descendants(xElementKey))
                    {
                        rs = new T();
                        rs.SetProperty(x);
                        l.Add(rs);
                    }
                    return l;
                case TwitterApiResponseFormat.Json:
                    foreach (var s in CreateJsonTextList(text))
                    {
                        rs = new T();
                        rs.SetProperty(s);
                        l.Add(rs);
                    }
                    return l;
                default: throw new InvalidOperationException();
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="data"></param>
        /// <param name="key"></param>
        /// <returns></returns>
        public static List<String> CreateJsonTextList(Dictionary<String, Object> data, String key)
        {
            if (data.ContainsKey(key) == false) { return new List<String>(); }
            var c = data[key] as JContainer;
            if (c == null) { return new List<string>(); }
            return CreateJsonTextList(c);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="jsonText"></param>
        /// <returns></returns>
        public static List<String> CreateJsonTextList(String jsonText)
        {
            JContainer jc = JsonConvert.DeserializeObject(jsonText) as JContainer;
            if (jc == null) { return new List<string>(); }
            return CreateJsonTextList(jc);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="container"></param>
        /// <returns></returns>
        public static List<String> CreateJsonTextList(JContainer container)
        {
            List<String> l = new List<string>();

            foreach (Object o in container)
            {
                l.Add(o.ToString());
            }
            return l;
        }
    }
}
